with Ada.Strings; use Ada.Strings;
with Ada.Strings.Unbounded;
with SDL.Keysym;
with Legend.Traces;
with Legend.Settings;
with Legend.StrRes;
with Legend.Colors;
with Text_Builder;
package body Legend.Items_Dialog is
   use type Interfaces.c.int;

   Items_Picture_Index : constant := 3501;
   Name_Height : constant := 48;
   Memo_Height : constant := 48;
   Item_Grid_Width  : constant := 48;
   Item_Grid_Height : constant := 48;
   Rows_Per_Page : constant := 3;
   Cols_Per_Row  : constant := 5;
   Border_Size : constant := 2;
   Table_Width : constant := Cols_Per_Row * Item_Grid_Width + Border_Size * 2;
   Table_Height : constant := Rows_Per_Page * Item_Grid_Height + Border_Size * 2;
   Scrollbar_Width  : constant := 20 + Border_Size * 2;
   Total_Width : constant := Table_Width + Scrollbar_Width;
   Total_Height : constant := Name_Height + Memo_Height + Table_Height;
   Margin_Top  : constant := 20;

   procedure Paint (this : in out Items_Dialog_Type)
   is
      use Interfaces.C;
      use type Item_Grid_Lists.Cursor;
      R : SDL.Video.Rect_t := (
         X => Int16_t(Renders.Screen.W - Total_Width) / 2,
         Y => Margin_Top,
         W => Total_Width,
         H => Total_Height);
      brush : Cairo.Context.Cairo_Context_Ref;
      first_cell : Table_Cell_Type := this.Table(this.First);
      focus_cell : Table_Cell_Type := this.Table(this.Focus);

      procedure Paint_Borders
      is
         x, y, w, h : double;
      begin
         this.Canvas.Set_Brush_Color(Colors.White);
         brush.Set_Line_Width(2.0);
         brush.Rectangle(0.0, 0.0, double(R.W), double(Name_Height));
         brush.Stroke;
         brush.Rectangle(0.0, double(Name_Height), double(R.W), double(Memo_Height));
         brush.Stroke;
         brush.Rectangle(0.0, double(Name_Height + Memo_Height), double(R.W), double(Table_Height));
         brush.Stroke;
         brush.Rectangle(double(Table_Width), double(Name_Height + Memo_Height), double(Scrollbar_Width), double(Table_Height));
         brush.Stroke;
         x := double((focus_cell.Col - 1) * Item_Grid_Width + 1);
         y := double(Name_Height + Memo_Height + (focus_cell.Row - first_cell.Row) * Item_Grid_Height + 1);
         w := double(Item_Grid_Width - 1);
         h := double(Item_Grid_Height - 1);
         brush.Rectangle(x, y, w, h);
         brush.Stroke;
      end Paint_Borders;

      procedure Paint_Titlebar
      is
         font_size : constant double := 16.0;
         padding_left : constant double := 5.0;
         padding_top : constant double := 5.0;
         item : Item_Type renames All_World.Items(focus_cell.Item_Grid.Id);
      begin
         this.Canvas.Set_True_Font(Unbounded.To_String(Settings.Dialog.Font.Name));
         brush.Set_Font_Size(font_size);
         -- NOTE : cairo use text baseline as y 
         brush.Move_To(padding_left, padding_top + font_size);
         declare
            caption : Unbounded.Unbounded_String;
         begin
            Unbounded.Append(caption, To_UTF8_Name(item.Name));
            -- luo pan
            if item.Id = Resources.Compass_Id then
               declare
                  p1 : Point_Type := All_World.Leader.Position_At_World;
                  p2 : Point_Type := All_World.Leader.Boat_Head_Position;
               begin
                  Unbounded.Append(
                     caption, 
                     " " & StrRes.Humen & "(" & p1.x'Img & "," & p1.y'Img & ")");
                  Unbounded.Append(
                     caption, 
                     " " & StrRes.Boat & "(" & p2.x'Img & "," & p2.y'Img & ")");
               end;
            end if;
            if item.Owner /= No_Hero then
               declare
                  owner : Hero_Type renames All_World.Heroes(item.Owner);
               begin
                  Unbounded.Append(caption, "  [" & To_UTF8_Name(owner.Name) & "]");
               end;
            elsif focus_cell.Item_Grid.Count > 1 then
               Unbounded.Append(caption, "   X " & focus_cell.Item_Grid.Count'Img);
            end if;
            brush.Show_Text(Unbounded.To_String(caption));
            brush.Stroke;
         end;
         brush.Move_To(padding_left, double(Name_Height) + padding_top + font_size);
         brush.Show_Text(To_UTF8_Name(item.Description));
         brush.Stroke;
      end Paint_Titlebar;

      procedure Paint_Item_Pictures
      is
         row : Natural := 1;
         col : Natural := 1;
         pos : Point_Type;
         pic : Picture_Type;
         grid : Item_Grid_Type;
         dummy : Interfaces.C.int;
      begin
         pos := (Border_Size + 1, Name_Height + Memo_Height + Border_Size + 1);
         for i in this.Table.Iterate(this.First) loop
            grid := Item_Grid_Lists.Element(i).Item_Grid;
            pic := this.Pictures(grid.Id + Resources.Bag_Item_Group.From);
            dummy := SDL.Video.Set_Alpha(pic.Surface, 0, 255);
            this.Canvas.Draw_Picture(pic, pos + (2, 2));
            col := col + 1;
            if col = Cols_Per_Row + 1 then
               col := 1;
               row := row + 1;
               exit when row = Rows_Per_Page + 1;
               pos.y := pos.y + Item_Grid_Height;
               pos.x := Border_Size + 1;
            else
               pos.x := pos.x + Item_Grid_Width;
            end if;
         end loop;
      end Paint_Item_Pictures;
   begin
      this.Canvas.Bind(R, Save_Region => True);
      this.Canvas.Clear((A => 128, others => 0));
      brush := this.Canvas.As_Brush;
      Paint_Borders;
      Paint_Titlebar;
      this.Canvas.Accept_Brush_Changed;
      Paint_Item_Pictures;
      this.Canvas.Accept_SDL_Changed;
   end Paint;

   procedure On_Timer (
      this          : in out Items_Dialog_Type;
      Timer         : Hash_Type;
      Count         : Natural;
      Cancel_Bubble : in out Boolean
      )
   is
   begin
      Interactives.Interactive_Type(this).On_Timer(Timer, Count, Cancel_Bubble);
      Cancel_Bubble := True;
   end On_Timer;

   procedure On_Key_Up (
      this : in out Items_Dialog_Type;
      Message : SDL.Events.Keyboard_Event_t;
      Cancel_Bubble : in out Boolean
      )
   is
      first_cell : Table_Cell_Type := this.Table(this.First);
      focus_cell : Table_Cell_Type := this.Table(this.Focus);
   begin
      case Message.Keysym.Sym is
         when SDL.Keysym.K_Escape  =>
            this.Focus := Item_Grid_Lists.No_Element;
            this.Canvas.Restore_Overlap_Surface;
            this.Close;
         when SDL.Keysym.K_Space =>
            this.Canvas.Restore_Overlap_Surface;
            this.Close;
         when SDL.Keysym.K_Up =>
            declare
               j : Item_Grid_Lists.Cursor := this.Focus;
            begin
               for i in 1 .. Cols_Per_Row loop
                  exit when not Item_Grid_Lists.Has_Element(j);
                  Item_Grid_Lists.Previous(j);
               end loop;
               if Item_Grid_Lists.Has_Element(j) then
                  this.Focus := j;
                  if this.Table(this.Focus).Row < first_cell.Row then
                     for i in 1 .. Cols_Per_Row loop
                        Item_Grid_Lists.Previous(this.First);
                     end loop;
                  end if;
                  this.Canvas.Invalidate;
               end if;
            end;
         when SDL.Keysym.K_Down =>
            declare
               j : Item_Grid_Lists.Cursor := this.Focus;
            begin
               for i in 1 .. Cols_Per_Row loop
                  exit when not Item_Grid_Lists.Has_Element(j);
                  Item_Grid_Lists.Next(j);
               end loop;
               if Item_Grid_Lists.Has_Element(j) then
                  this.Focus := j;
                  if this.Table(this.Focus).Row > first_cell.Row + 2 then
                     for i in 1 .. Cols_Per_Row loop
                        Item_Grid_Lists.Next(this.First);
                     end loop;
                  end if;
                  this.Canvas.Invalidate;
               end if;
            end;
         when SDL.Keysym.K_Left =>
            if focus_cell.Col > 0 then
               declare
                  j : Item_Grid_Lists.Cursor := Item_Grid_Lists.Previous(this.Focus);
               begin
                  if Item_Grid_Lists.Has_Element(j) then
                     this.Focus := j;
                     this.Canvas.Invalidate;
                  end if;
               end;
            end if;
         when SDL.Keysym.K_Right =>
            if focus_cell.Col < Cols_Per_Row then
               declare
                  j : Item_Grid_Lists.Cursor := Item_Grid_Lists.Next(this.Focus);
               begin
                  if Item_Grid_Lists.Has_Element(j) then
                     this.Focus := j;
                     this.Canvas.Invalidate;
                  end if;
               end;
            end if;
         when SDL.Keysym.K_U =>
            declare
               tb : Text_Builder.Builder_Type;
            begin
               for cell of this.Table loop
                  declare
                     item : Item_Type renames All_World.Items(cell.Item_Grid.Id);
                  begin
                     tb.Append(Traces.Image(item));
                  end;
               end loop;
               tb.Save_To_File("./bag.txt");
            end;
         when SDL.Keysym.K_T =>
            declare
               Item : Item_Type renames All_World.Items(focus_cell.Item_Grid.Id);
            begin
               case Item.Kind is
                  when ik_Study_Book =>
                     if Item.Kongfu = No_Kongfu then
                        if Item.Require_Material /= No_Item then
                           Trace_Log(
                              "material : " & Item.Require_Material'Img &  " " & 
                              To_UTF8_Name(All_World.Items(Item.Require_Material).Name));
                        end if;
                        for i in Item.Product_List'Range loop
                           declare
                              product : Uint16_t renames Item.Product_List(i);
                              count : Int16_t renames Item.Material_Count(i);
                           begin
                              if product /= No_Item then
                                 Trace_Log(
                                    "product : " & product'Img & " " &
                                    To_UTF8_Name(All_World.Items(product).Name));
                                 Trace_Log("need material count : " & count'Img);
                              end if;
                           end;
                        end loop;
                     end if;
                  when others =>
                     null;
               end case;
            end;
         when others =>
            null;
      end case;
   end On_Key_Up;

   procedure Setup (
      this : in out Items_Dialog_Type;
      Pictures : Pictures_Pointer := Resources.Outer_Images;
      Filter : Items_Filter_Type := null
      )
   is
      row, col : Natural := 1;
      procedure Append_Grid (Grid : Item_Grid_Type)
      is
      begin
         this.Table.Append((grid, row, col));
         col := col + 1;
         if col = Cols_Per_Row + 1 then
            col := 1;
            row := row + 1;
         end if;
      end Append_Grid;
   begin
      this.Pictures := Pictures;
      this.Filter := Filter;
      if this.Filter = null then
         for grid of All_World.Leader.Bag loop
            if grid.Id /= No_Item then
               Append_Grid(grid);
            end if;
         end loop;
      else
         for grid of All_World.Leader.Bag loop
            if grid.Id /= No_Item  then
               if this.Filter(All_World.Items(grid.Id)) then
                  Append_Grid(grid);
               end if;
            end if;
         end loop;
      end if;
      this.First := this.Table.First;
      this.Focus := this.First;
   end Setup;

   function Selected (this : in out Items_Dialog_Type) return Item_Grid_Type
   is
   begin
      if Item_Grid_Lists.Has_Element(this.Focus) then
         return this.Table(this.Focus).Item_Grid;
      else
         return (No_Item, 0);
      end if;
   end Selected;

end Legend.Items_Dialog;
